import { Controller, Get, Post, Body, Patch, Param, Delete, Inject, Res, UseGuards, ValidationPipe, Session, Query, Req } from '@nestjs/common';
import { LoginUserService } from './login-user.service';
import { CreateLoginUserDto } from './dto/create-login-user.dto';
import { UpdateLoginUserDto } from './dto/update-login-user.dto';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { JwtService } from '@nestjs/jwt';
import { Request, Response } from 'express';
import { LoginGuard } from '../login.guard';
import { LoginRefreshGuard } from '../loginRefresh.guard';
import { AuthGuard } from '@nestjs/passport';
import { IsPublic } from '../is-public.decorator';

declare module 'express' {
  interface Request {
    user: {
      userId: number,
      username: string
    }
  }
}
@Controller('login-user')
export class LoginUserController {
  constructor(private readonly loginUserService: LoginUserService) {}

  @Inject(JwtService)
  private jwtService: JwtService

  @Get('testToken')
  @UseGuards(LoginGuard)
  async testLogin() {
    return 'testLogin'
  }

  @Get('init')
  async initData() {
    await this.loginUserService.initData()
    return 'done'
  }

  @Post('login')
  async login(@Body(ValidationPipe) user: LoginDto, @Res({passthrough: true}) res: Response) {
    const foundUser = await this.loginUserService.login(user)
    if (foundUser) {
      const token = await this.jwtService.signAsync({
        user: {
          id: foundUser.id,
          username: foundUser.username
        }
      })
      res.setHeader('token', token)
      return 'login success'
    } else {
      return 'login fail'
    }
  }
  @Post('login_one_token_refresh')
  async loginOneTokenRefresh(@Body(ValidationPipe) user: LoginDto) {
    const foundUser = await this.loginUserService.login(user)
    if (foundUser) {
      const token = await this.jwtService.signAsync({
        username: foundUser.username
      }, {
        expiresIn:'7d'
      })
      return token
    } else {
      return 'login fail'
    }
  }
  @Post('login_refresh')
  async loginWithRefreshToekn(@Body(ValidationPipe) user: LoginDto, @Res({passthrough: true}) res: Response) {
    const foundUser = await this.loginUserService.login(user)
    if (foundUser) {
      const access_token = await this.jwtService.signAsync({
        user: {
          id: foundUser.id,
          username: foundUser.username
        }
      }, {
        expiresIn: '30m'
      })
      const refresh_token = this.jwtService.sign({
        userId: foundUser.id
      }, {
        expiresIn: '7d'
      })
      return {
        access_token,
        refresh_token
      }
    } else {
      return 'login fail'
    }
  }

  @Get('refresh')
  async refresh(@Query('refresh_token') refreshToken: string) {
    try {
      const data = this.jwtService.verify(refreshToken)
      const foundUser = await this.loginUserService.findByUserId(data.userId)
      const access_token = await this.jwtService.signAsync({
        user: {
          id: foundUser.id,
          username: foundUser.username
        }
      }, {
        expiresIn: '30m'
      })
      const refresh_token = this.jwtService.sign({
        userId: foundUser.id
      }, {
        expiresIn: '7d'
      })

      return {
        access_token,
        refresh_token
      }
    } catch (error) {
      
    }
  }

  @Post('loginBySession')
  async login2(@Body() user: LoginDto, @Session() session) {
    const foundUser = await this.loginUserService.login2(user)
    session.user = {
      username: foundUser.username,
      userId: foundUser.id
    }
    return 'success'
  }

  @Post('register')
  async register(@Body(ValidationPipe) user: RegisterDto) {
    await this.loginUserService.register(user)
  }

  @Post('loginByPassport')
  @UseGuards(AuthGuard('local'))
  async loginByPassport(@Req() req: Request) {
    console.log(req.user)
    const token = this.jwtService.sign({
      userId: req.user.userId,
      username: req.user.username
    }, {
      expiresIn: '0.5d'
    })
    return {
      token
    }
  }

  @IsPublic()
  @Get('login_github')
  @UseGuards(AuthGuard('github'))
  async loginWithGithub(@Req() req) {

  }

  @IsPublic()
  @Get('callback')
  @UseGuards(AuthGuard('github'))
  async loginWithGithubCallback(@Req() req) {
    return req.user
  }

  @IsPublic()
  @Get('login_google')
  @UseGuards(AuthGuard('google'))
  async loginWithGoogle(@Req() req) {

  }

  @IsPublic()
  @Get('callback/google')
  @UseGuards(AuthGuard('google'))
  async loginWithGoogleCallback(@Req() req) {
    if (!req.user) {
      return 'No user from google'
    }
    return {
      message: 'User information from google',
      user: req.user
    }
  }

}
